package org.future.dev.properties;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 读写属性文件
 * @author shixg
 * @date 2009-12-7 下午09:15:03
 */
public class PropertiesUtils {
    private String file_path = null;
    private Properties properties = null;
    /**
     * 构造函数
     * @param file_path :String
     */
    public PropertiesUtils(String file_path){
        this.file_path = file_path;
        File file = new File(file_path);
        FileInputStream in = null;
        try {
            String dir = file.getParent();
            if(needMkdirs(dir)){         // 需要创建目录时创建目录
                new File(dir).mkdirs();
            }
            if(!file.exists()){          // 文件不存在时创建文件
                file.createNewFile();
            }
            in = new FileInputStream(file_path);
            properties = new Properties();
            properties.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 根据 key 返回其 value
     * @param key :String
     * @return String
     */
    public String getValue(String key){
        if(properties == null){
            return null;
        }
        return properties.getProperty(key);
    }
    /**
     * 根据属性文件返回一个 databean
     * 该 databean 必须提供一个默认的 构造函数
     * @param cls :Class
     * @return Object
     */
    public Object getBean(Class cls){
        if(properties == null){
            return null;
        }
        Object obj = null;
        try {
            // 实例化一个对象
            Constructor cons = cls.getDeclaredConstructor();  // 默认构造函数
            obj = cons.newInstance();
            // 返回所有声明的域 ,包括 private 的域
            Field[] fds = cls.getDeclaredFields();
            // 构造 set 方法
            String fname = "";
            String setMethod = "";
            for(int i=0; i < fds.length; i++){
                fname = fds[i].getName();                 // 取出字段名称
                setMethod = "set"                         // 构造 set 方法
                    + Character.toUpperCase(fname.charAt(0))
                    + fname.substring(1);
                PropertyField f = fds[i].getAnnotation(PropertyField.class);
                if (f == null) {                          // 当前属性没有使用该注解
                    continue;
                }
                String key = f.key();                     // 取出当前字段所对应注解值key
                String val = getValue(key);               // 取出对象的属性值
                // 创建 Method 
                Method m = cls.getMethod(setMethod, String.class);
                // 调用 Method 方法
                m.invoke(obj, val);
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
    /**
     * 将 databean 保存到属性文件中
     * @param obj :Object
     */
    public void saveBean(Object obj){
        if(properties == null){
            return;
        }
        Class<? extends Object> cls = obj.getClass();
        try {
            // 返回所有声明的域 ,包括 private 的域
            Field[] fds = cls.getDeclaredFields();
            // 构造 get 方法
            String fname = "";
            String getMethod = "";
            for(int i=0; i < fds.length; i++){
                fname = fds[i].getName();                 // 取出字段名称
                getMethod = "get"                         // 构造 get 方法
                    + Character.toUpperCase(fname.charAt(0))
                    + fname.substring(1);
                PropertyField f = fds[i].getAnnotation(PropertyField.class);
                if (f == null) {                          // 当前属性没有使用该注解
                    continue;
                }
                String key = f.key();                     // 取出当前字段所对应注解值key
                // 创建 Method 
                Method m = cls.getMethod(getMethod);
                // 调用 Method 方法
                String val = (String)m.invoke(obj);
                setValue(key, val);
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 将属性文件保存到文件
        save();
    }
    /**
     * 设置属性值
     * @param key :String
     * @param value :String
     */
    public void setValue(String key,String value){
        if(properties == null){
            return;
        }
        properties.setProperty(key, value);
    }
    /**
     * 添加属性值
     * @param key :String
     * @param value :String
     */
    public void addValue(String key,String value){
        if(properties == null){
            return;
        }
        properties.put(key, value);
    }
    /**
     * 根据 key 移除属性
     * @param key :String
     */
    public void removeValue(String key){
        if(properties == null){
            return;
        }
        properties.remove(key);
    }
    /**
     * 保存当前属性文件
     */
    public void save(){
        if(properties == null){
            return;
        }
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file_path);
            properties.store(out, "##");
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(out != null){
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 是否需要创建目录
     * @param dir :String
     * @return boolean
     */
    private boolean needMkdirs(String dir){
        File d = new File(dir);
        String path = d.getAbsolutePath();
        // 判断是否是根目录
        Pattern pattern = Pattern.compile("^[A-Za-z]:(\\\\|/)$");
        Matcher matcher = pattern.matcher(path);
        boolean res = matcher.matches();
        if(d.exists() || res){         // 目录已存在 或者 是磁盘根目录时不需创建目录
            return false;
        }
        return true;
    }  
    
}
